home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Sample Code / Snippets / Toolbox / ZoomWindow / DoBetterWZoom.c < prev   
Encoding:
Text File  |  1993-02-15  |  4.8 KB  |  123 lines  |  [TEXT/MPS ]

  1. void DoZoomWindow (WindowPtr theWindow, short zoomDir, short hMax, short vMax)
  2. {
  3.     extern EventRecord    gTheEvent;                        // from the main event loop
  4.     extern Boolean        gHasColorQD;
  5.  
  6.     Rect                *windRect, *zoomRect;
  7.     Rect                globalPortRect, theSect, dGDRect;
  8.     GDHandle            nthDevice, dominantGDevice;
  9.     long                sectArea, greatestArea;
  10.  
  11.     if (TrackBox(theWindow, gTheEvent.where, zoomDir)) {
  12.         SetPort(theWindow);
  13.         EraseRect(&theWindow->portRect);    // recommended for cosmetic reasons
  14.  
  15.         if (zoomDir == inZoomOut) {
  16.  
  17.             /*
  18.              *    ZoomWindow() is a good basic tool, but it doesn't do everything necessary to
  19.              *    implement a good human interface when zooming. In fact it's not even close for
  20.              *    more high-end hardware configurations. We must help it along by calculating an
  21.              *    appropriate window size and location any time a window zooms out.
  22.              */
  23.  
  24.             windRect = &(**((WindowPeek) theWindow)->strucRgn).rgnBBox;
  25.             dominantGDevice = nil;
  26.             if (gHasColorQD) {
  27.  
  28.                 /*
  29.                  *    Color QuickDraw implies the possibility of multiple monitors. This is where
  30.                  *    zooming becomes more interesting. One should zoom onto the monitor containing
  31.                  *    the greatest portion of the window. This requires walking the gDevice list.
  32.                  */
  33.  
  34.                 nthDevice = GetDeviceList();
  35.                 greatestArea = 0;
  36.                 while (nthDevice != nil) {
  37.                     if (TestDeviceAttribute(nthDevice, screenDevice)) {
  38.                         if (TestDeviceAttribute(nthDevice, screenActive)) {
  39.                             SectRect(windRect, &(**nthDevice).gdRect, &theSect);
  40.                             sectArea = (long) rectWidth(theSect) * (long) rectHeight(theSect);
  41.                             if (sectArea > greatestArea) {
  42.                                 greatestArea = sectArea;        // save the greatest intersection
  43.                                 dominantGDevice = nthDevice;    // and which device it belongs to
  44.                             }
  45.                         }
  46.                     }
  47.                     nthDevice = GetNextDevice(nthDevice);
  48.                 }
  49.             }
  50.  
  51.             /*
  52.              *    At this point, we know the dimensions of the window we're zooming, and we know
  53.              *    what screen we're going to put it on. To be more specific, however, we need a
  54.              *    rectangle which defines the maximum dimensions of the resized window's contents.
  55.              *    This rectangle accounts for the thickness of the window frame, the menu bar, and
  56.              *    one or two pixels around the edges for cosmetic compatibility with ZoomWindow().
  57.              */
  58.  
  59.             if (dominantGDevice != nil) {
  60.                 dGDRect = (**dominantGDevice).gdRect;
  61.                 if (dominantGDevice == GetMainDevice())        // account for menu bar on main device
  62.                     dGDRect.top += GetMBarHeight();
  63.             }
  64.             else {
  65.                 dGDRect = qd.screenBits.bounds;                // if no gDevice, use default monitor
  66.                 dGDRect.top += GetMBarHeight();
  67.             }
  68.  
  69.             globalPortRect = theWindow->portRect;
  70.             LocalToGlobal(&topLeft(globalPortRect));        // calculate the window's portRect
  71.             LocalToGlobal(&botRight(globalPortRect));        // in global coordinates
  72.  
  73.             // account for the window frame and inset it a few pixels
  74.             dGDRect.left    += 2 + globalPortRect.left - windRect->left;
  75.             dGDRect.top        += 2 + globalPortRect.top - windRect->top;
  76.             dGDRect.right    -= 1 + windRect->right - globalPortRect.right;
  77.             dGDRect.bottom    -= 1 + windRect->bottom - globalPortRect.bottom;
  78.  
  79.             /*
  80.              *    Now we know exactly what our limits are, and since there are input parameters
  81.              *    specifying the dimensions we'd like to see, we can move and resize the zoom
  82.              *    state rectangle for the best possible results. We have three goals in this:
  83.              *    1. Display the window entirely visible on a single device.
  84.              *    2. Resize the window to best represent the dimensions of the document itself.
  85.              *    3. Move the window as short a distance as possible to achieve #1 and #2.
  86.              */
  87.  
  88.             zoomRect = &(**(WStateDataHandle) ((WindowPeek) theWindow)->dataHandle).stdState;
  89.  
  90.             /*
  91.              *    Initially set the zoom rectangle to the size requested by the input parameters,
  92.              *    although not smaller than a minimum size. We do this without moving the origin.
  93.              */
  94.  
  95.             zoomRect->right = (zoomRect->left = globalPortRect.left) +
  96.                                     max(hMax, MinWindowWidth(theWindow));
  97.             zoomRect->bottom = (zoomRect->top = globalPortRect.top) +
  98.                                     max(vMax, MinWindowHeight(theWindow));
  99.  
  100.             // Shift the entire rectangle if necessary to bring its origin inside dGDRect.
  101.             OffsetRect(zoomRect,
  102.                         max(dGDRect.left - zoomRect->left, 0),
  103.                         max(dGDRect.top - zoomRect->top, 0));
  104.  
  105.             /*
  106.              *    Shift the rectangle up and/or to the left if necessary to accomodate the view,
  107.              *    and if it is possible to do so. The rectangle may not be moved such that its
  108.              *    origin would fall outside of dGDRect.
  109.              */
  110.  
  111.             OffsetRect(zoomRect,
  112.                         -pin(zoomRect->right - dGDRect.right, 0, zoomRect->left - dGDRect.left),
  113.                         -pin(zoomRect->bottom - dGDRect.bottom, 0, zoomRect->top - dGDRect.top));
  114.  
  115.             // Clip expansion to dGDRect, in case view is larger than dGDRect.
  116.             zoomRect->right = min(zoomRect->right, dGDRect.right);
  117.             zoomRect->bottom = min(zoomRect->bottom, dGDRect.bottom);
  118.         }
  119.  
  120.         ZoomWindow(theWindow, zoomDir, false);        // all it needed was a brain transplant
  121.     }
  122. }
  123.